/**
 * 项目名：化工企业安全生产信息化管理平台
 * 日期：    2020-03-17 14:00:29
 * Copyright (c) 2015- -版权所有
 */

package com.joysuch.wwyt.edu.service.impl;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import com.google.common.base.Objects;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.joysuch.wwyt.bp.entity.BpDepart;
import com.joysuch.wwyt.bp.repository.BpDepartDao;
import com.joysuch.wwyt.common.enums.CommonTypes;
import com.joysuch.wwyt.common.repository.CommonTypeDao;
import com.joysuch.wwyt.common.service.CommonTypeService;
import com.joysuch.wwyt.core.common.ajax.ResultBean;
import com.joysuch.wwyt.core.common.util.DateTimeUtil;
import com.joysuch.wwyt.core.common.util.JsonUtil;
import com.joysuch.wwyt.core.common.util.PageDataUtils;
import com.joysuch.wwyt.core.common.util.PageDataUtils.PageDataConvert;
import com.joysuch.wwyt.core.common.util.SimpleDateFormatCache;
import com.joysuch.wwyt.core.exception.BusinessRestrictionsException;
import com.joysuch.wwyt.core.repository.BaseUserDao;
import com.joysuch.wwyt.core.service.BizCodeGeneratorFacade;
import com.joysuch.wwyt.core.support.Context;
import com.joysuch.wwyt.edu.bean.*;
import com.joysuch.wwyt.edu.bean.EduTrainningPlanListBean.SearchEduTrainningPlan;
import com.joysuch.wwyt.edu.bean.EduTrainningPlanStatisticsVo.SearchTrainningPlan;
import com.joysuch.wwyt.edu.entity.EduTrainningPlan;
import com.joysuch.wwyt.edu.entity.EduTrainningPlanCourse;
import com.joysuch.wwyt.edu.entity.EduTrainningRecord;
import com.joysuch.wwyt.edu.entity.EduTrainningRecordUser;
import com.joysuch.wwyt.edu.entity.dsl.QEduTrainningPlan;
import com.joysuch.wwyt.edu.enums.TrainingPlanStates;
import com.joysuch.wwyt.edu.mapper.EduCourtTrainningRecordMapper;
import com.joysuch.wwyt.edu.mapper.EduTrainningRecordMapper;
import com.joysuch.wwyt.edu.repository.*;
import com.joysuch.wwyt.edu.service.EduTrainningPlanService;
import com.joysuch.wwyt.util.PoiUtil;
import com.querydsl.core.types.ExpressionUtils;
import com.querydsl.core.types.Predicate;
import javafx.util.Pair;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.transaction.Transactional;
import java.io.IOException;
import java.net.URLEncoder;
import java.time.LocalDate;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
@Transactional
public class EduTrainningPlanServiceImpl implements EduTrainningPlanService {

    @Autowired
    private EduTrainningPlanDao dao;
    @Autowired
    private BizCodeGeneratorFacade bizCodeGeneratorFacade;
    @Autowired
    private CommonTypeDao commonTypeDao;
    @Autowired
    private CommonTypeService commonTypeService;
    @Autowired
    private BpDepartDao bpDepartDao;
    @Autowired
    private BaseUserDao baseUserDao;
    @Autowired
    private EduTrainningPlanCourseDao eduTrainningPlanCourseDao;
    @Autowired
    private EduCourseDao eduCourseDao;
    @Autowired
    private EduTrainningRecordDao eduTrainningRecordDao;

    @Resource
    private EduTrainningRecordUserDao eduTrainningRecordUserDao;
    @Autowired
    private EduCourseCoursewareDao courseCoursewareDao;
    @Resource
    private EduCourseStatisticsDao eduCourseStatisticsDao;
    @Resource
    private EduCoursewareDao eduCoursewareDao;
    @Resource
    private EduCourseLearnHistoryDao eduCourseLearnHistoryDao;

    @Resource
    private EduCourtTrainningRecordMapper eduCourtTrainningRecordMapper;

    @Autowired
    private EduTrainningRecordMapper  eduTrainningRecordMapper;

    @Override
    public EduTrainningPlan add(EduTrainningPlanEditBean entity) {
        Assert.isTrue(dao.countOfName(entity.getName().trim()) == 0, String.format("[%s]已存在", entity.getName()));
        EduTrainningPlan content = new EduTrainningPlan();
        if (StringUtils.isNotBlank(entity.getCode())) {
            Assert.isTrue(dao.countOfCode(entity.getCode()) == 0, String.format("编号%s已经存在", entity.getCode()));
            content.setCode(entity.getCode());
        } else {
            content.setCode(bizCodeGeneratorFacade.peiXunJiHua());
        }
        BeanUtils.copyProperties(entity, content, "id", "code");

        if (entity.getTrainningDepartId()!=null) {
            content.setTrainningDepartId(entity.getTrainningDepartId());
        }
        if (entity.getTrainningDepartIds() != null) {
            content.setDepartIds(JsonUtil.toJson(entity.getTrainningDepartIds()));//设置多个部门id
        } else {
            content.setDepartIds("[]");//设置多个部门id
        }
        content.setCreateTime(entity.getCreateTime());
        content.setName(entity.getName().trim());
        content.setCreateUserName(baseUserDao.getBaseUserNameById(Context.getCurrentUserId()));
        if (entity.getMakeDepartId() == null) {
            content.setMakeDepartId(Context.getCurrentDepartId());
        }
        content.setMyTrainStatus("未完成");
        setPlanState(content);
        dao.save(content);
        saveCourses(content, entity.getCourses(), true);
        if (entity.getTypeId() != null) {
            commonTypeService.updateTypeCount(CommonTypes.TRAINNING_PLAN, entity.getTypeId());
        }
        return content;
    }

    private void setPlanState(EduTrainningPlan plan){
        Date currDate = new Date();
        if (plan.getImplementTime() != null){
            if (currDate.before(plan.getImplementTime())){
                plan.setState(TrainingPlanStates.NOT_STARTED.getId());
            }
            if (plan.getFinishTime() != null && currDate.after(plan.getImplementTime()) && currDate.before(plan.getFinishTime())){
                plan.setState(TrainingPlanStates.INPROGRESSING.getId());
            }
            if (plan.getFinishTime() == null && currDate.after(plan.getImplementTime())){
                plan.setState(TrainingPlanStates.INPROGRESSING.getId());
            }
        }
        if (plan.getFinishTime() != null){
            if (plan.getFinishTime().before(currDate)){
                plan.setState(TrainingPlanStates.OUT_OF_DATE.getId());
            }
            if (plan.getImplementTime() == null && plan.getFinishTime().after(currDate)){
                plan.setState(TrainingPlanStates.NOT_STARTED.getId());
            }
        }
        if (plan.getState() == null){
            plan.setState(TrainingPlanStates.OUT_OF_DATE.getId());
        }
    }

    private void saveCourses(EduTrainningPlan content, List<Long> courseIds, boolean add) {
        if (!add) {
            eduTrainningPlanCourseDao.deleteByTrainningPlanId(content.getId());
        }
        if (courseIds == null || courseIds.isEmpty()) {
            return;
        }
        List<EduTrainningPlanCourse> courses = courseIds.stream().map(e -> {
            EduTrainningPlanCourse course = new EduTrainningPlanCourse();
            course.setCourseId(e);
            course.setTrainningPlanId(content.getId());
            return course;
        }).collect(Collectors.toList());
        eduTrainningPlanCourseDao.saveAll(courses);
    }

    @Override
    public void update(EduTrainningPlanEditBean entity) {
        Assert.isTrue(dao.countOfNameExcludeId(entity.getName().trim(), entity.getId()) == 0,
                String.format("[%s]已存在", entity.getName()));
        EduTrainningPlan content = dao.findById(entity.getId()).get();
        Long newId = entity.getTypeId();
        Long oldId = content.getTypeId();
        // Assert.notNull(entity.getCode(), "编号不能为空");
        // Assert.isTrue(dao.countOfCodeExcludeId(entity.getCode(), entity.getId()) == 0,
        // String.format("编号%s已经存在", entity.getCode()));
        // content.setCode(entity.getCode());
        BeanUtils.copyProperties(entity, content, "id", "code", "createUserName");
        if (entity.getTrainningDepartIds() != null) {
            content.setDepartIds(JsonUtil.toJson(entity.getTrainningDepartIds()));//设置多个部门id
        } else {
            content.setDepartIds("[]");//设置多个部门id
        }
        content.setName(entity.getName().trim());
        content.setCreateTime(entity.getCreateTime());
        Integer recordCount = eduTrainningRecordDao.countByPlanId(entity.getId());
        recordCount = recordCount == null ? 0 : recordCount;
        content.setMyTrainStatus(recordCount > 0 ? "已完成" : "未完成");
        setPlanState(content);
        dao.save(content);
        saveCourses(content, entity.getCourses(), false);
        if (!Objects.equal(newId, oldId)) {
            commonTypeService.updateTypeCount(CommonTypes.TRAINNING_PLAN, newId);
            commonTypeService.updateTypeCount(CommonTypes.TRAINNING_PLAN, oldId);
        }
        //只修改待发布 和未开始的培训
       List<EduTrainningRecord> list=eduCourtTrainningRecordMapper.selectByPlanId(content.getId());
        if (!CollectionUtils.isEmpty(list)){
            list.forEach(trainningRecord -> {
                trainningRecord.setTrainningTypeId(content.getTypeId());
                eduTrainningRecordMapper.updateById(trainningRecord);
            });
        }
    }

    /**
     *分页查询培训计划，
     * @param page
     * @param condition
     * @return
     */
    @Override
    public Page<EduTrainningPlanListBean> findByPage(Pageable page, SearchEduTrainningPlan condition) {
        Predicate predicate = prepareListSearchCondition(condition);
        Map<Long, BpDepart> departMap=new HashMap<>();
        Page<EduTrainningPlan> data = predicate == null ? dao.findAll(page) : dao.findAll(predicate, page);
        if (!data.isEmpty() && data.getContent()!=null) {
            Set<Long> deptIds=new HashSet<>();
            List<Long> makeDeptIds = data.getContent().stream().map(EduTrainningPlan::getMakeDepartId).collect(Collectors.toList());
            for (EduTrainningPlan eduTrainningPlan : data.getContent()) {
                String departIdStr = Strings.isNullOrEmpty(eduTrainningPlan.getDepartIds()) ? "[]" : eduTrainningPlan.getDepartIds();
                List<Long> longs = JsonUtil.fromListJson(departIdStr, Long.class);
                deptIds.addAll(longs);
            }
            deptIds.addAll(makeDeptIds);
            List<BpDepart> departList = bpDepartDao.findByIds(new ArrayList<>(deptIds));
            departMap= departList.stream().collect(Collectors.toMap(BpDepart::getId, Function.identity()));
        }
        Map<Long, BpDepart> finalDepartMap = departMap;
        return PageDataUtils.convertPageData(data, new PageDataConvert<EduTrainningPlanListBean, EduTrainningPlan>() {

            @Override
            public EduTrainningPlanListBean convert(EduTrainningPlan f) {
                EduTrainningPlanListBean bean = new EduTrainningPlanListBean();
                BeanUtils.copyProperties(f, bean);
                bean.setTypeName(commonTypeDao.getNameById(f.getTypeId()));
                if (finalDepartMap.get(f.getMakeDepartId()) != null) {
                    bean.setMakeDepartName(finalDepartMap.get(f.getMakeDepartId()).getName());
                }

                List<EduDepartBean> eduDepartBeanList = new ArrayList<>();
                String departIds = f.getDepartIds();
                if (Strings.isNullOrEmpty(departIds)) {
                    departIds = "[]";
                }
                List<Long> longs = JsonUtil.fromListJson(departIds, Long.class);
                StringBuffer trainDepartName = new StringBuffer();
                int count = 0;
                for (Long departId : longs) {
                    EduDepartBean eduDepartBean = new EduDepartBean();
                    eduDepartBean.setId(departId);
                    if (finalDepartMap.get(departId) != null) {
                        eduDepartBean.setName(finalDepartMap.get(departId).getName());
                    }
                    if (count > 0) {
                        trainDepartName.append(",");
                        if (finalDepartMap.get(departId) != null) {
                            trainDepartName.append(finalDepartMap.get(departId).getName());
                        }
                    } else {
                        if (finalDepartMap.get(departId) != null) {
                            trainDepartName.append(finalDepartMap.get(departId).getName());
                        }
                    }
                    eduDepartBeanList.add(eduDepartBean);
                    count++;
                }
                bean.setTrainningDepartName(trainDepartName.toString());
                bean.setEduDepartBeans(eduDepartBeanList);
                bean.setTrainningTeacherName(baseUserDao.getRealNameById(f.getTrainningTeacherId()));
                return bean;
            }
        });
    }

    private Predicate prepareListSearchCondition(SearchEduTrainningPlan condition) {
        Predicate p = null;
        QEduTrainningPlan q = QEduTrainningPlan.eduTrainningPlan;
        if (condition.getCodeOrNameOrCreateUser() != null) {
            String s = condition.getCodeOrNameOrCreateUser();
            p = ExpressionUtils.or(q.name.contains(s),
                    ExpressionUtils.or(q.code.contains(s), q.createUserName.contains(s)));
        }
        if (condition.getTypeId() != null) {
            p = ExpressionUtils.and(p, q.typeId.eq(condition.getTypeId()));
        }
        if (!StringUtils.isEmpty(condition.getMyTrainStatus())) {
            p = ExpressionUtils.and(p, q.myTrainStatus.eq(condition.getMyTrainStatus()));
        }
        if (condition.getDepartId() != null) {
            p = ExpressionUtils.and(p, q.makeDepartId.eq(condition.getDepartId()));
        }
        if (condition.getState() != null) {
            p = ExpressionUtils.and(p, q.state.eq(condition.getState()));
        }
        if (condition.getStartTime() != null) {
            p = ExpressionUtils.and(p, q.implementTime.goe(condition.getStartTime()));
        }
        if (condition.getEndTime() != null) {
            p = ExpressionUtils.and(p, q.implementTime.loe(condition.getEndTime()));
        }
        return p;
    }

    private Predicate prepareStatisticsSearchCondition(SearchTrainningPlan condition) {
        Predicate p = null;
        QEduTrainningPlan q = QEduTrainningPlan.eduTrainningPlan;
        if (condition.getName() != null) {
            p = ExpressionUtils.and(p, q.name.like("%"+condition.getName()+"%"));
        }
        if (condition.getTypeId() != null) {
            p = ExpressionUtils.and(p, q.typeId.eq(condition.getTypeId()));
        }
        if (!StringUtils.isEmpty(condition.getMyTrainStatus())) {
            p = ExpressionUtils.and(p, q.myTrainStatus.eq(condition.getMyTrainStatus()));
        }
        if (condition.getPlanYear() != null) {
            if (isNum(condition.getPlanYear())){
                p = ExpressionUtils.and(p, q.planYear.eq(Short.valueOf(condition.getPlanYear())));
            }
        }
        if (condition.getCode() != null) {
            p = ExpressionUtils.and(p, q.code.eq(condition.getCode()));
        }
        if (condition.getState() != null) {
            p = ExpressionUtils.and(p, q.state.eq(condition.getState()));
        }
        return p;
    }

    public Boolean isNum(String str) {
        try {
            new Short(str);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    @Override
    public void delete(Long id) throws BusinessRestrictionsException {
        // 校验业务逻辑是否允许删除。如本数据被其他业务关联，删除后导致其他业务不可用。不能删除时将抛出业务异常
        checkBussinessRestrictions(id);
        EduTrainningPlan plan = dao.getOne(id);
        dao.deleteById(id);
        commonTypeService.updateTypeCount(CommonTypes.TRAINNING_PLAN, plan.getTypeId());
    }

    /**
     * 校验业务逻辑是否允许删除。如本数据被其他业务关联，删除后导致其他业务不可用
     *
     * @param id 要删除的业务ID
     * @throws BusinessRestrictionsException 抛出的业务异常
     */
    private void checkBussinessRestrictions(Long id) throws BusinessRestrictionsException {
        List<EduTrainningRecord> recordList = eduTrainningRecordDao.findByTrainningPlanId(id);
        if (!CollectionUtils.isEmpty(recordList)) {
            throw new IllegalArgumentException("请先解除该培训计划与培训记录的绑定关系");
        }
    }

    @Override
    public EduTrainningPlan findById(Long id) {
        return dao.findById(id).orElse(null);
    }

    @Override
    public ResultBean eduTrainQuery() {
        List<EduTrainningPlan> all = dao.findByYear(LocalDate.now().getYear() + "");
        if (CollectionUtils.isEmpty(all)) {
            return ResultBean.success(EduExamReleaseDto.defaultDto());
        }
        Map<Integer, Long> map = all.stream().collect(Collectors.groupingBy(r -> DateTimeUtil.date2LocalDateTime(r.getCreateTime()).getMonthValue()
                , Collectors.counting()));
        for (int i = 1; i <= 12; i++) {
            map.putIfAbsent(i, 0L);
        }
        TreeMap<Integer, Long> treeMap = new TreeMap<>(map);
        return ResultBean.success(new EduExamReleaseDto(convertMonth(treeMap.keySet()), treeMap.values().stream().collect(Collectors.toList())));
    }

    @Override
    public void updateTrainStatus(Long planId) {
        Optional<EduTrainningPlan> op = dao.findById(planId);
        if (op.isPresent()) {
            EduTrainningPlan eduTrainningPlan = op.get();
            Integer cnt = eduTrainningRecordDao.countByPlanId(planId);
            if (cnt == 0) {
                eduTrainningPlan.setMyTrainStatus("未完成");
                eduTrainningPlan.setFinishTime(null);
            } else {
                eduTrainningPlan.setMyTrainStatus("已完成");
                if (eduTrainningPlan.getFinishTime() == null) {
                    eduTrainningPlan.setFinishTime(new Date());
                }
            }
            dao.save(eduTrainningPlan);
        }
    }

    @Override
    public List<Map<String,Object>> findByMyPage() {
        Long currentUserId = Context.getCurrentUserId();
        return dao.findUserPlans(currentUserId);
    }

    public ResultBean findByMyAllPage(Pageable pageable,String status,Integer state) {
        Long currentUserId = Context.getCurrentUserId();
        List<String> statusList = new ArrayList<>();
        if (StringUtils.isNotBlank(status)){
            statusList = Arrays.asList(status.split(","));
        }
        com.baomidou.mybatisplus.extension.plugins.pagination.Page<EduTrainingPlanListVo> page = new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(pageable.getPageNumber() + 1, pageable.getPageSize());
        com.baomidou.mybatisplus.extension.plugins.pagination.Page<EduTrainingPlanListVo> eduTrainingPlanListVoPage = eduCourtTrainningRecordMapper.findAllUserPlans(page,currentUserId, statusList,state);
        List<EduTrainingPlanListVo> records = eduTrainingPlanListVoPage.getRecords();
        return ResultBean.pageData(records, page.getTotal());
    }

    @Override
    public EduTrainingPlanDetailVo findDetail(Long trainingPlanId) {
        Long currentUserId = Context.getCurrentUserId();
        EduTrainingPlanDetailVo vo = new EduTrainingPlanDetailVo();
        //查询培训下课程
        vo.setCourseListBeans(queryCourses(trainingPlanId));
        //查询培训下培训记录
        List<EduTrainingRecordListVo> recordLists = Lists.newArrayList();
        List<EduTrainningRecord> trainingRecords = eduTrainningRecordDao.findByTrainningPlanId(trainingPlanId);
        trainingRecords.forEach(record->{
            EduTrainingRecordListVo recordVo = new EduTrainingRecordListVo();
            recordVo.setId(record.getId());
            recordVo.setCode(record.getCode());
            recordVo.setTrainingName(record.getTrainingName());
            recordVo.setTrainningDate(record.getTrainningDate());
            recordVo.setTrainningPlace(record.getTrainningPlace());
            recordVo.setTrainningTeacherId(record.getTrainningTeacherId());
            recordVo.setTrainningTeacherName(baseUserDao.getRealNameById(record.getTrainningTeacherId()));
            EduTrainningRecordUser user = eduTrainningRecordUserDao.getEduTrainingRecordUser(record.getId(),currentUserId);
            if (user != null){
                recordVo.setTrainningResult(user.getTrainningResult().equals("Y")?"合格":"不合格");
                recordLists.add(recordVo);
            }
        });
        vo.setRecordLists(recordLists);
        return vo;
    }

    @Override
    public Page<EduTrainningPlanStatisticsVo> findStatisticsPage(Pageable page, EduTrainningPlanStatisticsVo.SearchTrainningPlan condition) {
        Predicate predicate = prepareStatisticsSearchCondition(condition);

        Page<EduTrainningPlan> data = predicate == null ? dao.findAll(page) : dao.findAll(predicate, page);
        Integer userCount = baseUserDao.getEffectiveUserCount();
        return PageDataUtils.convertPageData(data, new PageDataConvert<EduTrainningPlanStatisticsVo, EduTrainningPlan>() {
            @Override
            public EduTrainningPlanStatisticsVo convert(EduTrainningPlan f) {
                EduTrainningPlanStatisticsVo bean = new EduTrainningPlanStatisticsVo();
                BeanUtils.copyProperties(f, bean);
                String departIds = f.getDepartIds();
                List<String> departNames = Lists.newArrayList();
                if (Strings.isNullOrEmpty(departIds)) {
                    departIds = "[]";
                }
                List<Long> longs = JsonUtil.fromListJson(departIds, Long.class);
                for (Long departId:longs) {
                    departNames.add(bpDepartDao.getNameById(departId));
                }
                bean.setTrainningDepartName(String.join(",",departNames));
                bean.setTypeName(commonTypeDao.getNameById(f.getTypeId()));
                //课程数量
                List<EduTrainningPlanCourse> courses = eduTrainningPlanCourseDao.findByTrainningPlanId(f.getId());
                bean.setCourseNum(CollectionUtils.isEmpty(courses)?0:courses.size());
                //课程完成人数
                int courseFinishUserNum = 0;
                for (EduTrainningPlanCourse course : courses){
                    List<Long> ids = courseCoursewareDao.findCoursewareIdsByCourseId(course.getCourseId());
                    if (CollectionUtils.isEmpty(ids)){
                        continue;
                    }
                    List<Long> userIds = eduCourseStatisticsDao.countLearnNum(ids);
                    List<Long> videoIds = eduCoursewareDao.findVideo(ids);
                    if (CollectionUtils.isEmpty(videoIds)){
                        courseFinishUserNum += userIds.size();
                        continue;
                    }
                    for (Long userId : userIds){
                        boolean flag = true;
                        for (Long coursewareId : videoIds){
                            Integer count = eduCourseLearnHistoryDao.countState(coursewareId,userId);
                            if (count <= 0){
                                flag = false;
                                break;
                            }
                        }
                        if (flag){
                            courseFinishUserNum += 1;
                        }
                    }
                }
                bean.setCourseFinishUserNum(courseFinishUserNum);
                //课程总人数
                bean.setCourseUserNum(userCount*bean.getCourseNum());
                //培训记录数量
                List<EduTrainningRecord> trainingRecords = eduTrainningRecordDao.findByTrainningPlanId(f.getId());
                bean.setTrainRecordNum(CollectionUtils.isEmpty(trainingRecords)?0:trainingRecords.size());
                //培训记录总人数
                AtomicReference<Integer> userNum = new AtomicReference<>(0);
                AtomicReference<Integer> nNoPassNum = new AtomicReference<>(0);
                AtomicReference<Integer> passNum = new AtomicReference<>(0);
                trainingRecords.forEach(record -> {
                    List<EduTrainningRecordUser> users = eduTrainningRecordUserDao.findByTrainningRecordId(record.getId());
                    if (!CollectionUtils.isEmpty(users)){
                        userNum.updateAndGet(v -> v + users.size());
                        users.forEach(user -> {
                            if (user.getTrainningResult().equals("Y")){
                                passNum.getAndSet(passNum.get() + 1);
                            }else {
                                nNoPassNum.getAndSet(nNoPassNum.get() + 1);
                            }
                        });
                    }
                });
                bean.setTrainRecordUserNum(userNum.get());
                //培训未通过人数
                bean.setTrainNoPassNum(nNoPassNum.get());
                //培训通过人数
                bean.setTrainPassNum(passNum.get());
                return bean;
            }
        });
    }

    public List<Long> retainElementList(List<List<Long>> elementLists) {
        Optional<List<Long>> result = elementLists.parallelStream()
                .filter(elementList -> elementList != null && elementList.size() != 0)
                .reduce((a, b) -> {
                    a.retainAll(b);
                    return a;
                });
        return result.orElse(new ArrayList<>());
    }

    @Override
    public void planExport(SearchTrainningPlan condition, HttpServletRequest request, HttpServletResponse response) {
        // 所有课程
        List<EduTrainningPlanStatisticsVo> dataList = planList(condition);
        String file = "培训计划" + DateUtil.format(new Date(), DatePattern.PURE_DATETIME_PATTERN) + ".xls";
        response.setContentType(request.getServletContext().getMimeType(file));
        HSSFWorkbook hwb = null;
        try {
            response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(new String(file.getBytes(), "UTF-8")));
            List<String> cellNames = Arrays.asList("培训计划名称", "培训计划编号", "培训类型", "培训部门", "开始时间", "结束时间", "状态", "课程数量"
                    , "课程总人数", "课程完成人数", "培训记录数量", "培训记录总人数", "培训通过人数", "培训未通过人数");
            Pair<HSSFWorkbook, HSSFSheet> pair = PoiUtil.getPoi("课程统计", cellNames);
            addCourseRecordData(dataList, pair);
            hwb = pair.getKey();
            hwb.write(response.getOutputStream());
        } catch (IOException e) {
            throw new IllegalArgumentException("excel导出失败，请联系系统管理员");
        } finally {
            if (hwb != null) {
                try {
                    hwb.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public List<EduTrainningPlanStatisticsVo> planList(SearchTrainningPlan condition) {
        Predicate predicate = prepareStatisticsSearchCondition(condition);

        List<EduTrainningPlan> data = predicate == null ? dao.findAll() : (List<EduTrainningPlan>)dao.findAll(predicate);
        if (!CollectionUtils.isEmpty(data)){
            data.sort(Comparator.comparing(EduTrainningPlan::getId).reversed());
        }
        //统计学员人数，目前是所有人
        Integer userCount = baseUserDao.getEffectiveUserCount();
        List<EduTrainningPlanStatisticsVo> list = Lists.newArrayList();
        data.forEach(f -> {
            EduTrainningPlanStatisticsVo bean = new EduTrainningPlanStatisticsVo();
            BeanUtils.copyProperties(f, bean);
            String departIds = f.getDepartIds();
            List<String> departNames = Lists.newArrayList();
            if (Strings.isNullOrEmpty(departIds)) {
                departIds = "[]";
            }
            List<Long> longs = JsonUtil.fromListJson(departIds, Long.class);
            for (Long departId:longs) {
                departNames.add(bpDepartDao.getNameById(departId));
            }
            bean.setTrainningDepartName(String.join(",",departNames));
            bean.setTypeName(commonTypeDao.getNameById(f.getTypeId()));
            //课程数量
            List<EduTrainningPlanCourse> courses = eduTrainningPlanCourseDao.findByTrainningPlanId(f.getId());
            bean.setCourseNum(CollectionUtils.isEmpty(courses)?0:courses.size());
            //课程完成人数
            int courseFinishUserNum = 0;
            for (EduTrainningPlanCourse course : courses){
                List<Long> ids = courseCoursewareDao.findCoursewareIdsByCourseId(course.getCourseId());
                if (CollectionUtils.isEmpty(ids)){
                    continue;
                }
                List<Long> userIds = eduCourseStatisticsDao.countLearnNum(ids);
                List<Long> videoIds = eduCoursewareDao.findVideo(ids);
                if (CollectionUtils.isEmpty(videoIds)){
                    courseFinishUserNum += userIds.size();
                    continue;
                }
                for (Long userId : userIds){
                    boolean flag = true;
                    for (Long coursewareId : videoIds){
                        Integer count = eduCourseLearnHistoryDao.countState(coursewareId,userId);
                        if (count <= 0){
                            flag = false;
                            break;
                        }
                    }
                    if (flag){
                        courseFinishUserNum += 1;
                    }
                }
            }
            bean.setCourseFinishUserNum(courseFinishUserNum);
            //课程总人数
            bean.setCourseUserNum(userCount*bean.getCourseNum());
            //培训记录数量
            List<EduTrainningRecord> trainingRecords = eduTrainningRecordDao.findByTrainningPlanId(f.getId());
            bean.setTrainRecordNum(CollectionUtils.isEmpty(trainingRecords)?0:trainingRecords.size());
            //培训记录总人数
            AtomicReference<Integer> userNum = new AtomicReference<>(0);
            AtomicReference<Integer> nNoPassNum = new AtomicReference<>(0);
            AtomicReference<Integer> passNum = new AtomicReference<>(0);
            trainingRecords.forEach(record -> {
                List<EduTrainningRecordUser> users = eduTrainningRecordUserDao.findByTrainningRecordId(record.getId());
                if (!CollectionUtils.isEmpty(users)){
                    userNum.updateAndGet(v -> v + users.size());
                    users.forEach(user -> {
                        if (user.getTrainningResult().equals("Y")){
                            passNum.getAndSet(passNum.get() + 1);
                        }else {
                            nNoPassNum.getAndSet(nNoPassNum.get() + 1);
                        }
                    });
                }
            });
            bean.setTrainRecordUserNum(userNum.get());
            //培训未通过人数
            bean.setTrainNoPassNum(nNoPassNum.get());
            //培训通过人数
            bean.setTrainPassNum(passNum.get());
            list.add(bean);
        });
        return list;
    }

    public void addCourseRecordData(List<EduTrainningPlanStatisticsVo> dataList, Pair<HSSFWorkbook, HSSFSheet> pair) {
        HSSFSheet sheet = pair.getValue();
        for (int i = 0; i < dataList.size(); i++) {
            EduTrainningPlanStatisticsVo vo = dataList.get(i);
            HSSFRow row = sheet.createRow(i + 1);
            row = sheet.createRow(i + 1);
            row.createCell(0).setCellValue(vo.getName());
            row.createCell(1).setCellValue(vo.getCode());
            row.createCell(2).setCellValue(vo.getTypeName());
            row.createCell(3).setCellValue(vo.getTrainningDepartName());
            if (vo.getImplementTime() != null){
                row.createCell(4).setCellValue(SimpleDateFormatCache.getYmdhms().format(vo.getImplementTime()));
            }
            if (vo.getFinishTime() != null){
                row.createCell(5).setCellValue(SimpleDateFormatCache.getYmdhms().format(vo.getFinishTime()));
            }
            if (vo.getState() != null){
                row.createCell(6).setCellValue(TrainingPlanStates.findNameById(vo.getState()));
            }
            row.createCell(7).setCellValue(vo.getCourseNum());
            row.createCell(8).setCellValue(vo.getCourseUserNum());
            row.createCell(9).setCellValue(vo.getCourseFinishUserNum());
            row.createCell(10).setCellValue(vo.getTrainRecordNum());
            row.createCell(11).setCellValue(vo.getTrainRecordUserNum());
            row.createCell(12).setCellValue(vo.getTrainPassNum());
            row.createCell(13).setCellValue(vo.getTrainNoPassNum());

        }
    }

    private List<String> convertMonth(Set<Integer> set) {
        return Lists.newArrayList(set).stream().map(r -> r + "月").collect(Collectors.toList());
    }

    /**
     * 新增培训部门id为多选后，已修改
     * @param id
     * @return
     */
    @Override
    public EduTrainningPlanDetailBean getById(Long id) {
        EduTrainningPlanDetailBean bean = new EduTrainningPlanDetailBean();
        EduTrainningPlan entity = findById(id);
        if (entity == null) {
            return null;
        }
        String departIds = entity.getDepartIds();
        if (Strings.isNullOrEmpty(departIds)) {
            departIds = "[]";
        }
//        bean.setTrainningDepartIds(departIds);
        List<Long> longs = JsonUtil.fromListJson(departIds, Long.class);
        bean.setTrainningDepartIds(longs);
        List<EduDepartBean> eduDepartBeanList = new ArrayList<>();
        StringBuilder trainDepartName = new StringBuilder();
        int count = 0;
        for (Long departId : longs) {
            EduDepartBean eduDepartBean = new EduDepartBean();
            String nameById = bpDepartDao.getNameById(departId);
            eduDepartBean.setId(departId);
            eduDepartBean.setName(nameById);
            eduDepartBeanList.add(eduDepartBean);

            if (count > 0){
                trainDepartName.append(",");
                trainDepartName.append(nameById);
            }else {
                trainDepartName.append(nameById);
            }
            count++;
        }
        bean.setEduDepartBeans(eduDepartBeanList);
        BeanUtils.copyProperties(entity, bean);
        bean.setTypeName(commonTypeDao.getNameById(entity.getTypeId()));
        bean.setMakeDepartName(bpDepartDao.getNameById(entity.getMakeDepartId()));
//        bean.setTrainningDepartName(bpDepartDao.getNameById(entity.getTrainningDepartId()));
        bean.setTrainningDepartName(trainDepartName.toString());
        bean.setTrainningTeacherName(baseUserDao.getRealNameById(entity.getTrainningTeacherId()));
        bean.setCourses(queryCourses(id));
        return bean;
    }

    private List<EduTrainningPlanCourseDetailBean> queryCourses(Long id) {
        List<EduTrainningPlanCourse> list = eduTrainningPlanCourseDao.findByTrainningPlanId(id);
        return list.stream().map(e -> {
            EduTrainningPlanCourseDetailBean detail = new EduTrainningPlanCourseDetailBean();
            detail.setId(e.getCourseId());
            detail.setName(eduCourseDao.getNameById(e.getCourseId()));
            return detail;
        }).collect(Collectors.toList());
    }

}
